package com.obelisco.modelo.dao.hibernate;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;
import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;
import org.springframework.orm.hibernate3.HibernateCallback;

import com.obelisco.exception.ObeliscoException;
import com.obelisco.modelo.dao.ICarpetaTransaccionDAO;
import com.obelisco.modelo.data.CarpetaTransaccion;
import com.obelisco.modelo.data.Grupo;
import com.obelisco.modelo.data.Sistema;
import com.obelisco.modelo.data.Transaccion;
import com.obelisco.modelo.data.Usuario;

public class CarpetaTransaccionDAO extends HibernateDAO<CarpetaTransaccion> implements
		ICarpetaTransaccionDAO {
	
	@Override
	public CarpetaTransaccion findByPK(Serializable clave) {
		CarpetaTransaccion data = (CarpetaTransaccion) getHibernateTemplate()
				.load(CarpetaTransaccion.class, clave);
		return data.getEstado().equals("B") ? null : data;
	}
	
	@Override
	public List<CarpetaTransaccion> loadAll() {
		@SuppressWarnings("unchecked")
		List<CarpetaTransaccion> lista = getHibernateTemplate()
				.find("from CarpetaTransaccion carpeta where carpeta.estado != 'B'");
		return lista;
	}

	@Override
	public CarpetaTransaccion findTree(Sistema sistema) {
		final Sistema aSistema = sistema;
		@SuppressWarnings("unchecked")
		List<CarpetaTransaccion> carpetasTransaccion = getHibernateTemplate().executeFind(
				new HibernateCallback() {

					private void recorrer(CarpetaTransaccion carpeta) {
						for (CarpetaTransaccion carpetaTransaccion : carpeta.getHijos()) {
							if (carpetaTransaccion.getHijos().size() >= 0)
								recorrer(carpetaTransaccion);

							for (Transaccion transaccion : carpetaTransaccion.getTransacciones()) {
								transaccion.getCodigo();
							}
						}
					}

					@Override
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {

						session.enableFilter("activo");
						Criteria c = session
								.createCriteria(CarpetaTransaccion.class);

						c.add(Expression.eq("sistema", aSistema));
						c.add(Expression.eq("nivel", new Integer(0)));
						
						@SuppressWarnings("unchecked")
						List<CarpetaTransaccion> carpetasTransaccion = c.list();

						for (CarpetaTransaccion carpetaRaiz : carpetasTransaccion)
							recorrer(carpetaRaiz);

						return carpetasTransaccion;
					}
				});

		CarpetaTransaccion carpetaRaiz = null;
		for (CarpetaTransaccion carpetaTransaccion : carpetasTransaccion)
			carpetaRaiz = carpetaTransaccion;

		return carpetaRaiz;
	}

	@Override
	public void delete(CarpetaTransaccion objeto) {
		((CarpetaTransaccion) objeto).setEstado("B");
		getHibernateTemplate().saveOrUpdate(objeto);
	}

	ClassValidator<CarpetaTransaccion> carpetaTransaccionValidator = new ClassValidator<CarpetaTransaccion>(
			CarpetaTransaccion.class,ResourceBundle.getBundle("com.obelisco.modelo.data.hibernate-validator"));
	
	public void validate(CarpetaTransaccion objeto) {
		
		if (objeto.getPadre() != null) {
			CarpetaTransaccion padre = objeto.getPadre();
			objeto.setRuta(padre.getRuta() + objeto.getNombre() + " / ");
		}

		InvalidValue[] validationMessages =  carpetaTransaccionValidator.getInvalidValues(objeto);

		StringBuffer errores = new StringBuffer();
		for (int i = 0; i < validationMessages.length; i++) {
			InvalidValue value = validationMessages[i];
			errores.append(value.getPropertyName() + " - "+ value.getMessage() + "<br/>");
		}

		if (errores.length() > 0) {
			
			throw new ObeliscoException(errores.toString());
		}

	}

	@Override
	public void save(CarpetaTransaccion objeto) {
		
		if (objeto.getPadre() != null) {
			CarpetaTransaccion padre = objeto.getPadre();
			objeto.setRuta(padre.getRuta() + objeto.getNombre() + " / ");
		}
		
		validate(objeto);
		getHibernateTemplate().saveOrUpdate(objeto);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<CarpetaTransaccion> findByProperty(String propertyName, Object value) {
		String queryString = "from CarpetaTransaccion modelo where modelo."
				+ propertyName + "= ?";
		return getHibernateTemplate().find(queryString, value);
	}

	private void recorrer(CarpetaTransaccion carpeta, Sistema sistema,
			Usuario usuario) {
		
		for (Iterator<CarpetaTransaccion> i = carpeta.getHijos().iterator(); i.hasNext();) {
			CarpetaTransaccion hijo = i.next();

			if (hijo.getHijos().size() >= 0) {
				recorrer(hijo, sistema, usuario);
				if (hijo.getTransacciones().isEmpty() && hijo.getHijos().isEmpty())
					i.remove();
			}

		}

		for (Iterator<Transaccion> j = carpeta.getTransacciones().iterator(); j.hasNext();) {
			Transaccion t = j.next();

			if (usuario.getGrupos().isEmpty())
				j.remove();
			else {			
				boolean conPermiso = false;
				for (Grupo grupo : usuario.getGrupos())
					if (grupo.getId().getSistema().equals(sistema))
						for (Transaccion tg : grupo.getTransacciones())			
							if (tg.equals(t)) {
								conPermiso = true;
								break;				
							}

				if (!conPermiso)
					j.remove();
			}

		}

	}

	@Override
	public CarpetaTransaccion findTree(Sistema sistema, Usuario usuario) {
		CarpetaTransaccion raiz = null;

		Session session = getSession();

		Criteria criteria = session.createCriteria(CarpetaTransaccion.class);
		criteria.add(Expression.eq("sistema", sistema));
		criteria.add(Expression.eq("nivel", new Integer(0)));

		@SuppressWarnings("unchecked")
		List<CarpetaTransaccion> carpetas = criteria.list();

		for (CarpetaTransaccion carpeta : carpetas) {
			recorrer(carpeta, sistema, usuario);
			raiz = carpeta;
		}
		
		return raiz;
	}

}
